package rov.data;


import java.util.Hashtable;
import java.io.File;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;


// provides thread-safe easy read/write access to user preferences
public class PreferencesManager
{
    public static final String LEFT_X_DEV = "left-x-dev";
    public static final String LEFT_Y_DEV = "left-y-dev";
    public static final String LEFT_TRIGGER_DEV = "left-trigger-dev";
    public static final String RIGHT_X_DEV = "right-x-dev";
    public static final String RIGHT_Y_DEV = "right-y-dev";
    public static final String RIGHT_TRIGGER_DEV = "right-trigger-dev";
    public static final String PUMP_DEV = "pump-dev";
    public static final String CAMERA_SERVO_DEV = "camera-servo-dev";

    public static final char KEY_VAL_SEPARATOR = '=';
    public static final char VAL_SEPARATOR = ',';
    public static final File DEFAULT_PREFS_FILE = new File(
                         System.getenv("HOME") + File.separatorChar + ".rovrc");

    private static final Object sInitLock = new Object();
    private static volatile PreferencesManager sDefault;


    public static final PreferencesManager getDefault() throws IOException
    {
        if (sDefault == null)
        {
            synchronized (sInitLock)
            {
                if (sDefault == null)
                {
                    sDefault = new PreferencesManager();
                    sDefault.load(DEFAULT_PREFS_FILE);
                }
            }
        }

        return sDefault;
    }


    public static final PreferencesManager getDefaultSimple(boolean silent)
    {
        try
        {
            return getDefault();
        }
        catch (FileNotFoundException e)
        {
            if (!silent)
                System.err.println("Could not find prefs file: \"" +
                                   DEFAULT_PREFS_FILE.getAbsolutePath() + "\"");
        }
        catch (IOException e)
        {
            if (!silent)
                e.printStackTrace();
        }

        try
        {
            return getDefault();
        }
        catch (IOException e)
        {
            if (!silent)
                e.printStackTrace();
        }

        return null;
    }


    private Hashtable<String,String> mPrefs;


    // use getDefault or getDefaultSilent to instantiate
    private PreferencesManager()
    {
        mPrefs = new Hashtable<String,String>();
    }


    // parses preference into a set of ints
    public Set<Integer> getInts(String name, Set<Integer> defaultVals)
    {
        String val = mPrefs.get(name);

        if (val == null)
        {
            if (defaultVals != null)
                set(name, defaultVals);

            return defaultVals;
        }

        String[] vals = val.split("" + VAL_SEPARATOR);
        HashSet<Integer> result = new HashSet<Integer>();

        for (String v : vals)
        {
            if (!v.isEmpty())
               result.add(Integer.parseInt(v.trim()));
        }

        return result;
    }


    // converts vals to a string, then calls set(String,String)
    public void set(String name, Set<Integer> vals)
    {
        StringBuffer result = new StringBuffer();

        for (Integer v : vals)
        {
            result.append(v);
            result.append(VAL_SEPARATOR);
        }

        set(name, result.toString());
    }


    // sets preference to val
    public void set(String name, String val)
    {
        mPrefs.put(name, val);
    }


    // load a preferences file
    // usually formatted something like:
    // key1=val1
    // key2=val2;val3;
    public synchronized void load(File f) throws IOException
    {
        BufferedReader in = new BufferedReader(new FileReader(f));
        String input = null;

        while ((input = in.readLine()) != null)
        {
            input = input.trim();

            int keyEnd = input.indexOf(KEY_VAL_SEPARATOR);
            String key = input.substring(0, keyEnd);
            String vals = input.substring(keyEnd + 1);

            mPrefs.put(key, vals);
        }
    }


    // saves prefs to the specified file
    // don't call setter methods while saving
    public synchronized void save(File f) throws IOException
    {
        PrintWriter out = new PrintWriter(new FileOutputStream(f));

        for (Map.Entry<String,String> entry : mPrefs.entrySet())
        {
            if (entry.getKey() != null && entry.getValue() != null)
                out.println(entry.getKey() + KEY_VAL_SEPARATOR + entry.getValue());
        }

        out.close();
    }


    // unit test
    public static void main(String[] args)
    {
        PreferencesManager pm = null;

        try
        {
            pm = getDefault();
        }
        catch (IOException e)
        {
            e.printStackTrace();

            try
            {
                pm = getDefault();
            }
            catch (IOException ex)
            {
                System.err.println("ERROR -- this should never happen:");
                ex.printStackTrace();
                System.err.println("failed");
                return;
            }
        }

        String key = "bla";
        HashSet<Integer> def = new HashSet<Integer>();

        def.add(1);
        def.add(4);

        Set<Integer> s = pm.getInts(key, null);

        System.out.println("key: \"" + key + "\"");

        if (s != null)
            for (Integer i : s)
                System.out.println("\t" + i);

        System.out.println("end");

        s = pm.getInts(key, def);

        System.out.println("key: \"" + key + "\"");

        if (s != null)
            for (Integer i : s)
                System.out.println("\t" + i);

        System.out.println("end");

        s = pm.getInts(key, null);

        System.out.println("key: \"" + key + "\"");

        if (s != null)
            for (Integer i : s)
                System.out.println("\t" + i);

        System.out.println("end");

        if (args.length > 0)
        {
            pm.set(key, def);

            try
            {
                pm.save(DEFAULT_PREFS_FILE);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }

        System.out.println("success");
    }
}
